import re
from rest_framework.throttling import SimpleRateThrottle
from abc import abstractmethod, ABC
from django.core.cache import caches
from base_config.cache_config import THROTTLE_CACHE_NAME
from base_config.mysql_config import MYSQL_NAME


# 重写了限制频率的方法，原始只能支持1/s,m,h,d , 不能支持5分钟一次，10秒中一次
class BaseThrottle(SimpleRateThrottle, ABC):
    """
    支持更灵活速率格式的节流器基类
    支持格式: '3/10m' (10分钟3次), '5/2h' (2小时5次), '1/d' (每天1次)
    """

    RATE_REGEX = r"^(\d+)/(?:(\d+)([smhd]))$|^(\d+)/([smhd])$"
    DURATION_MAP = {"s": 1, "m": 60, "h": 3600, "d": 86400}
    cache = caches[THROTTLE_CACHE_NAME]  # 使用的cache
    scope = None  # 构建cache_key

    def parse_rate(self, rate):
        """解析速率字符串，返回请求次数和持续时间(秒)"""
        if rate is None:
            return (None, None)

        match = re.match(self.RATE_REGEX, rate)
        if not match:
            raise ValueError(
                f"无效的速率格式: {rate}. "
                "支持格式: '3/10m' (10分钟3次), '1/m' (每分钟1次)"
            )

        groups = match.groups()

        # 处理带数字的周期 (如 10m)
        if groups[1] and groups[2]:
            num_requests = int(groups[0])
            period_num = int(groups[1])
            period_unit = groups[2]
        # 处理单字符周期 (如 m)
        else:
            num_requests = int(groups[3])
            period_unit = groups[4]
            period_num = 1

        duration = self.DURATION_MAP.get(period_unit)
        if duration is None:
            raise ValueError(f"无效的时间单位: {period_unit}. 允许: s, m, h, d")

        return (num_requests, duration * period_num)

    @abstractmethod
    def get_cache_key(self, request, view):
        pass

    @abstractmethod
    def get_rate(self):
        pass


# 对请求源的IP进行限制
class IPThrottle(BaseThrottle):
    # 在settings中配置频率时使用到的关键字，有scope来指定
    scope = "IP"

    def get_cache_key(self, request, view):
        # 这里return什么，就以什么作为限制,上面的scope本来就是用于这里去配置文件中获取rate的
        pref = MYSQL_NAME
        ip = self.get_ident(request)
        scope = self.scope
        return f"{pref}:throttle_{scope}:{ip}"

    # 可以在这里设置访问频率
    def get_rate(self):
        return "180/m"
